/****************************************
File: main.cpp

This file is part of Model-loader

Copyright (C) 1999 David Stibbe (dstibbe@gmail.com)
                     and Gerrit Jan Jansen

Stellar is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
****************************************/

#include "framework.h"

//for the camera :=)
GLdouble eyeX;
GLdouble eyeY;
GLdouble eyeZ;
GLdouble centerX;
GLdouble centerY;
GLdouble centerZ;
GLdouble upX;
GLdouble upY;
GLdouble upZ;

float xyv[3],zv[3];
float nv1[]={0,1,0};
float nv2[]={1,0,0};

int c[]={0,0,0};
int bx[]={-10,0,0};
int ex[]={10,0,0};
int by[]={0,-10,0};
int ey[]={0,10,0};
int bz[]={0,0,-10};
int ez[]={0,0,100};

int bxby[]={-10,-10,0};
int bxey[]={-10,10,0};
int exey[]={10,10,0};
int exby[]={10,-10,0};

float angle1,angle2;
float scale=1;
float angle1_backup;
float angle2_backup;

int start=1;
int numberOfVerticesC;	// aantal vertices in het model
vertex *verticesC;			// alle vertices van het model
int numberOfFacesC;		// aantal faces in het model
face *facesC;				// alle faces van het model
int* con;

int vwF,vwB;

void loadModel(int numberOfVertices,vertex* vertices,int numberOfFaces,face* faces ){
	float* p1;
	float* p2;
	float* p3;
	float e1[3],e2[3],n[3];
	int i,j;

	numberOfVerticesC=numberOfVertices;
	verticesC=vertices;
	numberOfFacesC=numberOfFaces;
	facesC=faces;

	con=new int[numberOfVertices];



	for(j=0;j<numberOfVertices;j++)
		con[j]=0;

	for(i=0;i<numberOfFaces;i++){
		p1=verticesC[facesC[i].vertex[0]].pos;
		p2=verticesC[facesC[i].vertex[1]].pos;
		p3=verticesC[facesC[i].vertex[2]].pos;

		con[facesC[i].vertex[0]]++;
		con[facesC[i].vertex[1]]++;
		con[facesC[i].vertex[2]]++;

		for(j=0;j<3;j++){
			e1[j]=p2[j]-p1[j];
			e2[j]=p3[j]-p1[j];
		}

		normalVector(e1,e2,n);


		facesC[i].normal[M_X]=n[M_X];
		facesC[i].normal[M_Y]=n[M_Y];
		facesC[i].normal[M_Z]=n[M_Z];

		for(j=0;j<3;j++){
			verticesC[facesC[i].vertex[j]].normal[M_X]+=n[M_X];
			verticesC[facesC[i].vertex[j]].normal[M_Y]+=n[M_Z];
			verticesC[facesC[i].vertex[j]].normal[M_Z]+=n[M_Z];
		}

	}
	for(i=0;i<numberOfVertices;i++){
		verticesC[i].normal[M_X]/=con[i];
		verticesC[i].normal[M_Y]/=con[i];
		verticesC[i].normal[M_Z]/=con[i];
	}

}

int viewFront(){
	return (vwF=!vwF);
}

int viewBack(){
	return (vwB=!vwB);
}

void mouseButtonDown(float x, float y) {
	printf("mouseButtonDown op (%f, %f)\n", x, y);
}

void mouseButtonUp(float x, float y) {
	printf("mouseButtonUp op (%f, %f)\n", x, y);
}

void mouseDrag(float x, float y) {
	printf("Mousedrag naar (%f, %f)\n", x, y);
}

void doDrawing(int opdracht) {
	if(start){
		start=0;
		glPushMatrix();
		gluLookAt (eyeX,eyeY,eyeZ,centerX,centerY,centerZ,upX,upY,upZ);
		glPushMatrix();
	}

	printf("doDrawing() voor opdracht '%d'\n", opdracht);

	plotAxes();

	switch(opdracht){
	case WIREFRAME:
		drawWireFrame();
		break;
    case USE_COLOR:
		drawColorFrame();
		break;
	case USE_NORMAL:
		drawFillFrame();
		break;
	case USE_NORMAL_SMOOTH:
		drawFillSmoothFrame();
		break;
	}

}

void plotAxes(){
	glLineWidth(1.0);
	glBegin(GL_LINES);
		glColor3f(1.0, 0.0, 0.0);

			glVertex3iv(bx);
			glVertex3iv(ex);

			glVertex3iv(bxby);
			glVertex3iv(exby);

			glVertex3iv(bxey);
			glVertex3iv(exey);

		glColor3f(0.0, 1.0, 0.0);
			glVertex3iv(by);
			glVertex3iv(ey);

			glVertex3iv(bxby);
			glVertex3iv(bxey);

			glVertex3iv(exby);
			glVertex3iv(exey);

		glColor3f(0.0, 0.0, 1.0);
			glVertex3iv(bz);
			glVertex3iv(ez);
	glEnd();
}


void drawWireFrame(){

	glLineWidth(1.0);
	glColor3f(1.0, 1.0, 1.0);
	for(int i=0;i<numberOfFacesC;i++)
	{
		glBegin(GL_LINE_LOOP);
			glVertex3fv(verticesC[facesC[i].vertex[0]].pos);
			glVertex3fv(verticesC[facesC[i].vertex[1]].pos);
			glVertex3fv(verticesC[facesC[i].vertex[2]].pos);
		glEnd();
	}
}


void drawColorFrame(){
	int i;

	glShadeModel (GL_SMOOTH);

	GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0 };
	GLfloat light_diffuse[] = { 0.5, 0.5, 0.5, 1.0};
	GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat light_position[] = { 10.0, 10.0, 10.0, 0.0 };

	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);


	if(vwB || vwF){
		if(!(vwF && vwB)){
			glEnable(GL_CULL_FACE);
			if(vwF)
				glCullFace(GL_BACK);
			if(vwB)
				glCullFace(GL_FRONT);
		}

		glColor3f(0.0, 0.0, 1.0);
		for(i=0;i<numberOfFacesC;i++){
			glBegin(GL_TRIANGLES);
				glVertex3fv(verticesC[facesC[i].vertex[0]].pos);
				glVertex3fv(verticesC[facesC[i].vertex[1]].pos);
				glVertex3fv(verticesC[facesC[i].vertex[2]].pos);
			glEnd();
		}

	glDisable(GL_CULL_FACE);

	}

	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHTING);
}



void drawFillFrame(){
	int i;

	glShadeModel (GL_SMOOTH);

	GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0 };
	GLfloat light_diffuse[] = { 0.5, 0.5, 0.5, 1.0};
	GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat light_position[] = { 10.0, 10.0, 10.0, 0.0 };

	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);


	if(vwB || vwF){
		if(!(vwF && vwB)){
			glEnable(GL_CULL_FACE);
			if(vwF)
				glCullFace(GL_BACK);
			if(vwB)
				glCullFace(GL_FRONT);
		}

		glColor3f(0.0, 0.0, 1.0);
		for(i=0;i<numberOfFacesC;i++){
			glBegin(GL_TRIANGLES);
				glNormal3fv(facesC[i].normal);
				glVertex3fv(verticesC[facesC[i].vertex[0]].pos);
				glVertex3fv(verticesC[facesC[i].vertex[1]].pos);
				glVertex3fv(verticesC[facesC[i].vertex[2]].pos);
			glEnd();
		}

	glDisable(GL_CULL_FACE);

	}

	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHTING);
}

void drawFillSmoothFrame(){
	int i;

	glShadeModel (GL_SMOOTH);

	GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0 };
	GLfloat light_diffuse[] = { 0.5, 0.5, 0.5, 1.0};
	GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat light_position[] = { 10.0, 10.0, 10.0, 0.0 };

	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);


	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);


	if(vwB || vwF){
		if(!(vwF && vwB)){
			glEnable(GL_CULL_FACE);
			if(vwF)
				glCullFace(GL_BACK);
			if(vwB)
				glCullFace(GL_FRONT);
		}

		glColor3f(0.0, 0.0, 0.0);
		for(i=0;i<numberOfFacesC;i++){
			glBegin(GL_TRIANGLES);
				glNormal3fv(verticesC[facesC[i].vertex[0]].normal);
				glVertex3fv(verticesC[facesC[i].vertex[0]].pos);

				glNormal3fv(verticesC[facesC[i].vertex[1]].normal);
				glVertex3fv(verticesC[facesC[i].vertex[1]].pos);

				glNormal3fv(verticesC[facesC[i].vertex[2]].normal);
				glVertex3fv(verticesC[facesC[i].vertex[2]].pos);
			glEnd();
		}

		glDisable(GL_CULL_FACE);
	}

	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHTING);
}



void zoom(float z){
	scale+=z/100.0;
	transform();


}
void moveY(float da){
	angle1+=da;
	angle1_backup+=da;
	if(angle1_backup>360.0)
		angle1_backup-=360.0;
	if(angle1_backup<0.0)
		angle1_backup+=360.0;
	transform();
}

void moveX(float da){
	angle2+=da;
	angle2_backup+=da;
	if(angle2_backup>360.0)
		angle2_backup-=360.0;
	if(angle2_backup<0.0)
		angle2_backup+=360.0;
	transform();
}

void transform(){
	if(scale!=1){
		glPopMatrix();
		glPopMatrix();
		glPushMatrix();
		eyeX/=scale;
		eyeY/=scale;
		eyeZ/=scale;
		gluLookAt (eyeX,eyeY,eyeZ,centerX,centerY,centerZ,upX,upY,upZ);
		glPushMatrix();
		scale=1;

		glRotatef(angle1_backup,nv1[M_X],nv1[M_Y],nv1[M_Z]);
		glRotatef(angle2_backup,nv2[M_X],nv2[M_Y],nv2[M_Z]);
	}

	if(angle1!=0 || angle2!=0){
		glPopMatrix();
		glPushMatrix();
		glRotatef(angle1_backup,nv1[M_X],nv1[M_Y],nv1[M_Z]);
		glRotatef(angle2_backup,nv2[M_X],nv2[M_Y],nv2[M_Z]);
		angle1=0;
	}

	printf("angle_backup1: %f\n",angle1_backup);
	printf("angle_backup2: %f\n",angle2_backup);

}

void normalVector(float e1[],float e2[],float n[]){
	float t;
	n[M_X]=e1[M_Y]*e2[M_Z] - e1[M_Z]*e2[M_Y];
	n[M_Y]=e1[M_Z]*e2[M_X] - e1[M_X]*e2[M_Z];
	n[M_Z]=e1[M_X]*e2[M_Y] - e1[M_Y]*e2[M_X];
	t=sqrt(n[M_X]*n[M_X]+n[M_Y]*n[M_Y]+n[M_Z]*n[M_Z]);

	if(t!=0){
		n[M_X]/=t;
		n[M_Y]/=t;
		n[M_Z]/=t;
	}
}

void step(float rotationIncrement) {
	moveY(-rotationIncrement);
	printf("step\n");
}





void reset() {

	eyeX=10;
	eyeY=10;
	eyeZ=10;
	centerX=0;
	centerY=0;
	centerZ=0;
	upX=0;
	upY=0;
	upZ=1;


	float dx=eyeX-centerX;
	float dy=eyeY-centerY;
	float dz=eyeZ-centerZ;


	zv[M_X]=dx;
	zv[M_Y]=dy;
	zv[M_Z]=dz;

	xyv[M_X]=dx;
	xyv[M_Y]=dy;
	xyv[M_Z]=0;

	//normalVector(zv,xyv,nv1);
	//normalVector(zv,nv1,nv2);


	printf("draai-as: (%f,%f,%f)\n",nv1[0],nv1[1],nv1[2]);

	scale=1;
	angle1=0;
	angle2=0;

	if(!start){
		glPopMatrix();
		glPopMatrix();
		glPushMatrix();

		gluLookAt (eyeX,eyeY,eyeZ,centerX,centerY,centerZ,upX,upY,upZ);
		glPushMatrix();
	}

	angle1_backup=0;
	angle2_backup=0;

	printf("reset\n");
}

int main(int argc, char *argv[]) {
	if (argc != 2) {
		fprintf(stderr, "Usage: %s filename.cgm\n", argv[0]);
		exit(-1);
	}

	// laad het model
	if (!readModel(argv[1])) {
		fprintf(stderr, "Could not read model %s\n", argv[1]);
		exit(-1);
	}

	vwF=0;
	vwB=0;

	// maak het window aan
	createWindow(1, argv);

	// zet de positie van het figuur
	reset();
	// start de mainloop
	return Fl::run();
}

